#include<iostream>
#include<string>
#include<queue>
#include<pthread.h>

template <class T>
class BlockQueue
{
private:
    //判断队列是否为满(满就入不了队列)
    bool IsFull()
    {
        return _bq.size() == _cap;
    }
    //判断队列是否为空(为空出不了队列)
    bool IsEmpty()
    {
        return _bq.size() == 0;
    }
public:
    BlockQueue(int cap)//构造
        :_cap(cap)
    {
        pthread_mutex_init(&_mutex,nullptr);//锁的初始化
        //条件变量的初始化
        pthread_cond_init(&_product_cond,nullptr);
        pthread_cond_init(&_consumer_cond,nullptr);
        _product_wait_n = 0;
        _consumer_wait_n = 0;
    }

    //生产者用的接口(入阻塞队列)
    void Enqueue(T &in)
    {
        pthread_mutex_lock(&_mutex);

        while(IsFull())
        {
            _product_wait_n++;

            pthread_cond_wait(&_product_cond,&_mutex);//生产者等待消费者唤醒

            _product_wait_n--;
        }
        //走到这已经被唤醒了
        //生产者开始生产
        _bq.push(in);
        // std::cout<<in<<std::endl;

        //pthread_cond_signal(&_consumer_cond);
        if(_consumer_wait_n > 0)//如果有等待的消费者唤醒消费者来消费
        {
            pthread_cond_signal(&_consumer_cond);
        }
        pthread_mutex_unlock(&_mutex);
    }



    //消费者用的接口(出队列)
    void Pop(T *out)
    {
        pthread_mutex_lock(&_mutex);
        while(IsEmpty())
        {
            _consumer_wait_n++;

            pthread_cond_wait(&_consumer_cond,&_mutex);

            _consumer_wait_n--;
        }

        //走到这已经被唤醒了
        //开始消费
        *out = _bq.front();
        // std::cout<<out<<std::endl;
        _bq.pop();
        //唤醒生产者来生产
        pthread_cond_signal(&_product_cond);
        if(_product_wait_n>0)
        {
            pthread_cond_signal(&_product_cond);
        }
        pthread_mutex_unlock(&_mutex);
    }
    // void Enqueue(const T &in) // 生产者用的接口
    // {
    //     pthread_mutex_lock(&_mutex);
    //     while(IsFull())//判断队列是否已经满了
    //     {
    //         pthread_cond_wait(&_product_cond, &_mutex); //满的时候就在此情况下等待
    //     }
    //     // 进行生产
    //     _bq.push(in);
    //     // 通知消费者来消费
    //     pthread_cond_signal(&_consumer_cond);
    //     pthread_mutex_unlock(&_mutex);
    // }
    // void Pop(T *out) // 消费者用的接口
    // {
    //     pthread_mutex_lock(&_mutex);
    //     while(IsEmpty())
    //     {
    //         pthread_cond_wait(&_consumer_cond, &_mutex); 
    //     }

    //     // 进行消费
    //     *out = _bq.front();
    //     _bq.pop();
    //     // 通知生产者来生产
    //     pthread_cond_signal(&_product_cond);
    //     pthread_mutex_unlock(&_mutex);
    // }

    //析构
    ~BlockQueue()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_product_cond);
        pthread_cond_destroy(&_consumer_cond);
    }
private:
    std::queue<T> _bq;
    int _cap;//队列上限
    pthread_mutex_t _mutex;
    pthread_cond_t _product_cond;//生产者的
    pthread_cond_t _consumer_cond;//消费者的

    int _product_wait_n;//生产者的阻塞数
    int _consumer_wait_n;//消费者的阻塞数
};